package xyz.mumuwei.youthcourseserver.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import xyz.mumuwei.youthcourseserver.common.dto.EmailDto;
import xyz.mumuwei.youthcourseserver.common.dto.LoginUserDto;
import xyz.mumuwei.youthcourseserver.common.lang.Const;
import xyz.mumuwei.youthcourseserver.common.lang.Result;
import xyz.mumuwei.youthcourseserver.pojo.User;
import xyz.mumuwei.youthcourseserver.service.AuthorityService;
import xyz.mumuwei.youthcourseserver.service.RoleService;
import xyz.mumuwei.youthcourseserver.service.UserService;
import xyz.mumuwei.youthcourseserver.service.WechatService;
import xyz.mumuwei.youthcourseserver.utils.*;

import javax.mail.MessagingException;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import java.util.UUID;


/**
 * 登陆相关请求
 * @author mumuwei
 * @date 2022/2/20
 */
@Slf4j
@Validated
@RestController
@RequiredArgsConstructor
public class LoginController {

    final UserService userService;
    final RoleService roleService;
    final AuthorityService authorityService;
    final EmailUtil emailUtil;
    final RedisUtil redisUtil;
    final WechatService wechatService;

    /**
     * 【登录】
     * 用户使用【用户名、邮箱、手机号】 和【密码】进行登录
     * 登录会判断用户账号状态，若被锁定，可提示
     * 短信登录待开发
     * @param loginUser 用户登录提交表单对象
     * @return 登录成功返回用户除密码外的账户信息，失败返回错误消息
     */
    @PostMapping("/login")
    public Result login(@Validated LoginUserDto loginUser){
        return userService.login(loginUser);
    }

    /**
     * 【邮箱登录】
     * 使用发送至邮箱的验证码进行登录
     */
    @PostMapping("/login/email")
    public Result loginByEmailCode(EmailDto emailDto){
        if(!RegexUtil.emali(emailDto.getEmail())){
            return Result.fail("邮箱账号格式有误！");
        }
        if (!redisUtil.get(Const.EMAIL_CODE_HEAD_REDIS + emailDto.getEmail()).equals(emailDto.getCode())) {
            return Result.fail("验证码校验失败，请重新登录！");
        }
        redisUtil.delete(Const.EMAIL_CODE_HEAD_REDIS + emailDto.getEmail());
        User user = userService.getOne(new QueryWrapper<User>().eq("email", emailDto.getEmail()));
        return userLoginInfo(user);
    }

    /**
     * 【校验】
     * 用户注册时，校验用户名是否存在
     */
    @GetMapping("/validUsername")
    public Result validUsername(@NotBlank(message = "用户名不能为空") String username){
        User user = userService.getOne(new QueryWrapper<User>().eq("username", username));
        if(user == null){
            return Result.success();
        }
        return Result.fail("用户名已存在！");
    }

    /**
     * 【校验】
     * 验证邮箱是否注册
     */
    @GetMapping("/validEmail")
    public Result validEmail(@Email(message = "邮箱格式不正确") String email){
        User user = userService.getOne(new QueryWrapper<User>().eq("email", email));
        if(user == null){
            return Result.success();
        }
        return Result.fail("邮箱已被注册！");
    }

    /**
     * 【校验】
     * 验证手机号是否被注册
     */
    @GetMapping("/validPhone")
    public Result validPhone(String phone){
        if (!RegexUtil.phone(phone)) {
            return Result.fail("手机号格式不正确！");
        }
        User user = userService.getOne(new QueryWrapper<User>().eq("phone", phone));
        if(user == null){
            return Result.success();
        }
        return Result.fail("手机号已被绑定！");
    }

    /**
     * 【用户名注册】
     */
    @PostMapping("/register")
    public Result register(@Validated LoginUserDto loginUser){
        return userService.register(loginUser);
    }

    /**
     * 【邮箱注册】
     * 使用邮箱注册账户，发送邮件到用户邮箱
     */
    @GetMapping("/getEmail")
    public Result getEmail(User newUser) throws MessagingException {
        if (userService.getOne(new QueryWrapper<User>().eq("email", newUser.getEmail())) != null) {
            return Result.fail("邮箱已被注册！");
        }
        String uuid = UUID.randomUUID().toString().replace("-", "");
        User user = new User();
        user.setEmail(newUser.getEmail());
        user.setKeyword(newUser.getKeyword());
        redisUtil.set("email:register:" + uuid, user, 20*60*1000);
        EmailDto emailDto = new EmailDto();
        emailDto.setEmail(newUser.getEmail());
        emailDto.setPath("/register/"+uuid);
        String[] to = { newUser.getEmail() };
        emailUtil.thymeleafEmail(to, "注册", emailDto, "email/register", "");
        return Result.success();
    }

    /**
     * 【邮箱注册】
     * 用户通过邮件中的链接进行注册
     */
    @GetMapping("/register/{uuid}")
    public Result registerByEmail(@PathVariable("uuid") String uuid, @Email @RequestParam("email") String email){
        if (userService.getOne(new QueryWrapper<User>().eq("email", email)) != null) {
            return Result.fail("邮箱已被注册！");
        }
        User u = (User) redisUtil.get("email:register:" + uuid);
        // 校验匹配
        if (email.equals(u.getEmail())) {
            User user = new User();
            String username = GenerateCodeUtil.generateUsername();
            while (userService.getOne(new QueryWrapper<User>().eq("username", username)) != null){
                username = GenerateCodeUtil.generateUsername();
            }
            user.setUsername(username);
            user.setEmail(email);
            user.setKeyword(u.getKeyword());
            // 设置默认角色
            user.setRoleId(Const.STUDENT_ROLE_CODE);
            userService.save(user);
            redisUtil.delete("email:register:" + uuid);
            // 设置默认角色
            return Result.success("注册成功！");
        }
        return Result.fail("校验错误，注册失败！");
    }

    /**
     * 【邮箱验证码登录】
     * 邮箱发送验证码
     * 通过验证码进行登录
     */
    @GetMapping("/getEmailCode")
    public Result getCodeByEmail(@Email String email) throws MessagingException {
        if (userService.getOne(new QueryWrapper<User>().eq("email", email)) == null) {
            return Result.fail("用户不存在！");
        }
        return sendEmail(email);
    }

    /**
     * 【换绑邮箱 验证码】
     * 用户换绑邮箱时发送验证码
     */
    @GetMapping("/bandEmail/code")
    public Result sendEmailByBand(@Email String email) throws MessagingException {
        if (userService.getOne(new QueryWrapper<User>().eq("email", email)) != null) {
            return Result.fail("邮箱已被绑定！");
        }
        return sendEmail(email);
    }

    /**
     * 发送邮箱验证码
     */
    private Result sendEmail(String email) throws MessagingException {
        String c = (String) redisUtil.get(Const.EMAIL_CODE_HEAD_REDIS + email);
        if(c != null){
            return Result.fail("验证码已发送，请勿重复请求！");
        }
        // 生成6位数字验证码
        String code = GenerateCodeUtil.generateCode();
        redisUtil.set(Const.EMAIL_CODE_HEAD_REDIS + email, code, 5*60*1000);
        EmailDto emailDto = new EmailDto();
        emailDto.setCode(code);
        String[] to = { email };
        emailUtil.thymeleafEmail(to, "【青少年兴趣课管理系统】登录验证码", emailDto, "email/validateCode", "");
        return Result.success("验证码已发送至邮箱，请登录查看");
    }

    /**
     * 换绑邮箱校 验证码
     */
    @PostMapping("/bandEmail/band")
    public Result validEmailAndCode(@RequestAttribute Integer uid, @RequestParam String code, @RequestParam String number){
        log.error("uid={},code={},number={}", uid, code, number);
        if(!RegexUtil.emali(number)){
            return Result.fail("邮箱账号格式有误！");
        }
        if (!redisUtil.get(Const.EMAIL_CODE_HEAD_REDIS + number).equals(code)) {
            return Result.fail("验证码校验失败，请重新登录！");
        }
        redisUtil.delete(Const.EMAIL_CODE_HEAD_REDIS + number);
        User user = new User();
        user.setId(uid);
        user.setEmail(number);
        boolean update = userService.updateById(user);
        if(update){
            return Result.success("绑定邮箱成功");
        }
        return Result.fail("绑定邮箱失败");
    }

    /**
     * 根据用户id获取用户路由表
     */
    @GetMapping("/router")
    public Result getRouterList(@RequestAttribute Integer uid){
        User user = userService.getById(uid);
        return authorityService.getAuthListByRoleId(user.getRoleId());
    }

    /**
     * 登录成功后返回用户信息封装
     * 设置用户密码为空
     * 更新登录时间
     */
    private Result userLoginInfo(User user){
        user.setKeyword("");
        // 判断账号是否锁定
        if(user.getState() == 0){
            // 更新登录时间
            User u = new User();
            u.setId(user.getId());
            u.setLastLoginTime(String.valueOf(System.currentTimeMillis()).substring(0,10));
            userService.updateById(u);
            // 创建token
            user.setToken(JwtTokenUtil.generateToken(user));
            return Result.success("登陆成功", user);
        }else {
            return Result.fail("登录失败，账号被锁定！请联系管理员。");
        }
    }

    /**
     * 微信登录接口
     * @param code 用户登录凭证
     * @return 返回登录 token
     */
    @GetMapping("/login/wechat/{code}")
    public Result wechatLogin(@PathVariable @NotBlank(message = "校验码不能为空")String code) {
        return wechatService.login(code);
    }

    /**
     * 获取手机验证码
     * @param phone 手机号
     * @return 发送结果
     */
    @PostMapping("/send/phone")
    public Result sendPhoneValidCode(String phone) {
        log.info("phone: {}", phone);
        return userService.sendPhoneCode(phone);
    }

    /**
     * 退出登录
     * @param uid 账户id
     * @return 退出结果
     */
    @GetMapping("/logout")
    public Result logout(@RequestAttribute Integer uid) {
        return Result.success();
    }

    /**
     * 获取系统内账户、教师、学生、管理员等数量
     */
    @GetMapping("/userNum")
    public Result getUserNums() {
        return userService.getUserNums();
    }
}
